package pe.com.ValoracionVivienda.views.prediccion;

import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.util.List;

import org.apache.commons.lang3.SerializationUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.eclipse.jface.viewers.ComboViewer;
import org.eclipse.jface.viewers.ISelectionChangedListener;
import org.eclipse.jface.viewers.IStructuredContentProvider;
import org.eclipse.jface.viewers.IStructuredSelection;
import org.eclipse.jface.viewers.LabelProvider;
import org.eclipse.jface.viewers.SelectionChangedEvent;
import org.eclipse.jface.viewers.StructuredSelection;
import org.eclipse.jface.viewers.Viewer;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.ScrolledComposite;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Group;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.MessageBox;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.ToolBar;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.wb.swt.SWTResourceManager;

import pe.com.ValoracionVivienda.domain.entities.Entrenamiento;
import pe.com.ValoracionVivienda.domain.entities.EntrenamientoItemEntrada;
import pe.com.ValoracionVivienda.domain.entities.EntrenamientoModelo;
import pe.com.ValoracionVivienda.domain.tipos.TipoValoracion;
import pe.com.ValoracionVivienda.service.impl.EntrenamientoServiceJpaImpl;
import pe.com.ValoracionVivienda.service.interfaces.EntrenamientoService;
import pe.com.ValoracionVivienda.views.resource.shared.SP3ResourceShared;
import weka.classifiers.functions.MultilayerPerceptron;
import weka.core.Instance;

public class CompPredicciones extends Composite {

	private final int ANCHO_LABEL = 164;
	private final int ALTO_LABEL = 15;
	private final int ANCHO_INPUT = 131;
	private final int ALTO_INPUT = 21;
	
	private final int INC_Y_LABEL = 36;
	private final int INC_Y_INPUT = 36;
	
	private final int POS_IZQUIERDA_X_LABEL = 10; 
	private final int POS_DERECHA_X_LABEL = 361;
	private final int POS_IZQUIERDA_X_INPUT = 180;
	private final int POS_DERECHA_X_INPUT = 531; 
	
	private Label[] labels;
	private Text[] inputs;
	
	private Integer idTipoTasacion;
	private ComboViewer comboViewer;
	private Composite composite;
	private ScrolledComposite scrolledComposite;
	private Text txtPrecio;
	private Entrenamiento entrenamiento;
	private Group grpDataEntrada;
	
	/**
	 * Create the composite.
	 * @param parent
	 * @param style
	 */
	public CompPredicciones(Composite parent, int style) {
		super(parent, SWT.NONE);
		setLayout(new GridLayout(3, false));
		
		ToolBar toolBar = new ToolBar(this, SWT.FLAT | SWT.RIGHT);
		toolBar.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false, 3, 1));
		
		ToolItem tltmPredecir = new ToolItem(toolBar, SWT.NONE);
		tltmPredecir.setImage(SWTResourceManager.getImage(CompPredicciones.class, "/pe/com/ValoracionVivienda/images/check.png"));
		tltmPredecir.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				menuPredecir();
			}
		});
		tltmPredecir.setText("Predecir");
		
		Label lblEntrenamiento = new Label(this, SWT.NONE);
		GridData gd_lblEntrenamiento = new GridData(SWT.RIGHT, SWT.CENTER, false, false, 1, 1);
		gd_lblEntrenamiento.widthHint = 87;
		lblEntrenamiento.setLayoutData(gd_lblEntrenamiento);
		lblEntrenamiento.setText("Entrenamiento");
		
		Combo cboEntrenamiendo = new Combo(this, SWT.READ_ONLY);
		GridData gd_cboEntrenamiendo = new GridData(SWT.LEFT, SWT.CENTER, true, false, 1, 1);
		gd_cboEntrenamiendo.widthHint = 190;
		cboEntrenamiendo.setLayoutData(gd_cboEntrenamiendo);
		
		comboViewer = new ComboViewer(cboEntrenamiendo);
		comboViewer.addSelectionChangedListener(new ISelectionChangedListener() {
			public void selectionChanged(SelectionChangedEvent event) {
				IStructuredSelection selection = (IStructuredSelection)event.getSelection();
				Entrenamiento entrenamiento = (Entrenamiento)selection.getFirstElement();
				LoadInputsPrediccion(entrenamiento.getId());
			}
		});
		comboViewer.setContentProvider(new IStructuredContentProvider() {
			@Override
			public void inputChanged(Viewer viewer, Object oldInput, Object newInput) {
				System.out.println("Input changed: old=" + oldInput + ", new=" + newInput);
			}
			
			@Override
			public void dispose() {
				System.out.println("Disposing... ComboViewer");
			}
			
			@Override
			public Object[] getElements(Object inputElement) {
				Entrenamiento[] entrenamientos = (Entrenamiento[]) inputElement;
				return entrenamientos;
			}
		});
		comboViewer.setLabelProvider(new LabelProvider(){
			@Override
			public String getText(Object element){
				return ((Entrenamiento)element).getNombre();
			}
		});
		
		new Label(this, SWT.HORIZONTAL);
		
		Label lblPrecio = new Label(this, SWT.NONE);
		lblPrecio.setText("Precio");
		
		txtPrecio = new Text(this, SWT.BORDER | SWT.READ_ONLY);
		GridData gd_txtPrecio = new GridData(SWT.LEFT, SWT.CENTER, false, false, 1, 1);
		gd_txtPrecio.widthHint = 206;
		txtPrecio.setLayoutData(gd_txtPrecio);
		new Label(this, SWT.NONE);
		
		grpDataEntrada = new Group(this, SWT.NONE);
		grpDataEntrada.setText("Data entrada");
		FillLayout fl_grpDataEntrada = new FillLayout(SWT.HORIZONTAL);
		fl_grpDataEntrada.marginHeight = 2;
		grpDataEntrada.setLayout(fl_grpDataEntrada);
		grpDataEntrada.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true, 3, 1));
		
		scrolledComposite = new ScrolledComposite(grpDataEntrada, SWT.H_SCROLL | SWT.V_SCROLL);
		scrolledComposite.setExpandHorizontal(true);
		scrolledComposite.setExpandVertical(true);
		
		composite = new Composite(scrolledComposite, SWT.NONE);
		
		scrolledComposite.setContent(composite);
		scrolledComposite.setMinSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
	}
	
	protected void LoadInputsPrediccion(Integer idEntrenamiento) {
		EntrenamientoService entrenamientoService = new EntrenamientoServiceJpaImpl();
		List<EntrenamientoItemEntrada> itemsEntrada = entrenamientoService.getItemsEntradaPorEntrenamientoId(idEntrenamiento);
		entrenamientoService.close();
		
		labels = new Label[itemsEntrada.size()];
		inputs = new Text[itemsEntrada.size()];
		
		int yLabel=21;
		int yInput=18;
		
		for (Control control : composite.getChildren()) {
			control.dispose();
		}
		
		for(int i = 0; i < itemsEntrada.size(); i++){
			labels[i] = new Label(composite, SWT.WRAP);
			inputs[i] = new Text(composite, SWT.BORDER);
			
			// labels
			labels[i].setText(itemsEntrada.get(i).getNombre());
			if(i % 2 == 0){
				labels[i].setBounds(POS_IZQUIERDA_X_LABEL, yLabel, ANCHO_LABEL, ALTO_LABEL);
			} else {
				labels[i].setBounds(POS_DERECHA_X_LABEL, yLabel, ANCHO_LABEL, ALTO_LABEL);
				yLabel += INC_Y_LABEL;
			}
			labels[i].redraw();
			labels[i].update();
			
			// inputs
			inputs[i].setData(itemsEntrada.get(i).getNombre());
			if(i % 2 == 0){
				inputs[i].setBounds(POS_IZQUIERDA_X_INPUT, yInput, ANCHO_INPUT, ALTO_INPUT);
			} else {
				inputs[i].setBounds(POS_DERECHA_X_INPUT, yInput, ANCHO_INPUT, ALTO_INPUT);
				yInput += INC_Y_INPUT;
			}
		}
		
		scrolledComposite.setMinSize(composite.computeSize(SWT.DEFAULT, SWT.DEFAULT));
		txtPrecio.setText("");
	}

	protected void menuPredecir() {
		if (!validarCombo()){
			MessageBox messageBox = new MessageBox(this.getShell(), SWT.ICON_WARNING | SWT.OK);
			messageBox.setText(SP3ResourceShared.getString("SP3"));
			messageBox.setMessage(SP3ResourceShared.getString("Debe_seleccionar") + " un entrenamiento");
			messageBox.open();
			return ;
		} else {
			predecirPrecio();
		}
	}

	private void predecirPrecio() {
		double valorPredicho;
		EntrenamientoService entrenamientoService = new EntrenamientoServiceJpaImpl();
		EntrenamientoModelo entrenamientoModelo = entrenamientoService.getModeloPorEntrenamientoId(entrenamiento.getId());
		entrenamientoService.close();
		
		// weka
		MultilayerPerceptron multilayerPerceptron = (MultilayerPerceptron) SerializationUtils.deserialize(entrenamientoModelo.getModelo());
		Instance instance = new Instance(labels.length + 1);
		
		try{
			for (int i = 0; i < inputs.length; i++) {
				instance.setValue(i, Double.parseDouble(inputs[i].getText()));
			}
		} catch (NumberFormatException e){
			e.printStackTrace();
			Logger logger = LogManager.getLogger(CompPredicciones.class.getName());
			logger.error(ExceptionUtils.getStackTrace(e));
			return ;
		}
		
		instance.setValue(inputs.length, 0);
		try {
			DecimalFormatSymbols dfs = new DecimalFormatSymbols();
			dfs.setDecimalSeparator('.');
			dfs.setGroupingSeparator(',');
			DecimalFormat decimalFormat = new DecimalFormat("#.###", dfs);
			
			double[] distForIns = multilayerPerceptron.distributionForInstance(instance);
			valorPredicho = distForIns[0];
			txtPrecio.setText(decimalFormat.format(valorPredicho));
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private boolean validarCombo() {
		boolean isValido = true;
		
		IStructuredSelection selection = (IStructuredSelection)comboViewer.getSelection();
		entrenamiento = (Entrenamiento) selection.getFirstElement();
		
		if (entrenamiento == null)
			isValido = false;
		
		return isValido;
	}

	public void initData(TipoValoracion tipoValoracion, Integer idTipoTasacion){
		this.idTipoTasacion = idTipoTasacion;
		
		LoadComboEntrenamiento();
	}

	private void LoadComboEntrenamiento() {
		EntrenamientoService entrenamientoService = new EntrenamientoServiceJpaImpl();
		Entrenamiento[] entrenamientos = entrenamientoService.getEntrenamientosPorIdTipoTasacion(idTipoTasacion).toArray(new Entrenamiento[0]);
		comboViewer.setInput(entrenamientos);
		
		if (entrenamientos.length != 0){
			IStructuredSelection selection = new StructuredSelection(entrenamientos[0]);
			comboViewer.setSelection(selection);
		}
	}

	@Override
	protected void checkSubclass() {
		// Disable the check that prevents subclassing of SWT components
	}
}
